package com.atguigu.tingshu.album.service.impl;

import com.atguigu.tingshu.album.mapper.AlbumAttributeValueMapper;
import com.atguigu.tingshu.album.mapper.AlbumInfoMapper;
import com.atguigu.tingshu.album.mapper.AlbumStatMapper;
import com.atguigu.tingshu.album.mapper.TrackInfoMapper;
import com.atguigu.tingshu.album.service.AlbumInfoService;
import com.atguigu.tingshu.common.constant.RabbitConstant;
import com.atguigu.tingshu.common.constant.SystemConstant;
import com.atguigu.tingshu.common.execption.GuiguException;
import com.atguigu.tingshu.common.result.ResultCodeEnum;
import com.atguigu.tingshu.common.util.AuthContextHolder;
import com.atguigu.tingshu.model.album.AlbumAttributeValue;
import com.atguigu.tingshu.model.album.AlbumInfo;
import com.atguigu.tingshu.model.album.AlbumStat;
import com.atguigu.tingshu.model.album.TrackInfo;
import com.atguigu.tingshu.model.search.AttributeValueIndex;
import com.atguigu.tingshu.query.album.AlbumInfoQuery;
import com.atguigu.tingshu.vo.album.AlbumAttributeValueVo;
import com.atguigu.tingshu.vo.album.AlbumInfoVo;
import com.atguigu.tingshu.vo.album.AlbumListVo;
import com.atguigu.tingshu.vo.album.AlbumStatVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.stream.Collectors;

@Slf4j
@Service
@SuppressWarnings({"unchecked", "rawtypes"})
public class AlbumInfoServiceImpl extends ServiceImpl<AlbumInfoMapper, AlbumInfo> implements AlbumInfoService {

    @Autowired
    private AlbumInfoMapper albumInfoMapper;
    @Autowired
    private AlbumAttributeValueMapper albumAttributeValueMapper;
    @Autowired
    private AlbumStatMapper albumStatMapper;
    @Autowired
    private TrackInfoMapper trackInfoMapper;
    @Autowired
    private RabbitTemplate rabbitTemplate;
    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    @Lazy  //等使用时在从容器中装配
    AlbumInfoService albumInfoService;


    @Transactional(rollbackFor = Exception.class)
    @Override
    public void saveAlbumInfo(AlbumInfoVo albumInfoVo) {
        //1.先保存专辑数据
        AlbumInfo albumInfo = new AlbumInfo();
        BeanUtils.copyProperties(albumInfoVo, albumInfo);  //拷贝属性
        //设置前端还没有提交的属性，需要后端查询或者自己设置的属性值
        //1.1设置用户id，避免数据库全查
        albumInfo.setUserId(AuthContextHolder.getUserId());
        //1.2专辑中包含声音的数量.默认为0
        albumInfo.setIsFinished(0);
        //1.3是否完结：0-否；1-完结；需要根据属性值判断
        List<AlbumAttributeValueVo> albumAttributeValueVoList = albumInfoVo.getAlbumAttributeValueVoList();
        if(!CollectionUtils.isEmpty(albumAttributeValueVoList)){
            albumAttributeValueVoList.forEach(albumAttributeValueVo -> {
                if(albumAttributeValueVo.getValueId().equals(SystemConstant.ALBUM_IS_FINISH)) //>>8.完结常量类，避免硬编码
                {   //"专辑是否完结：0-否；1-完结；"
                    albumInfo.setIsFinished(1);}
            });
        }
        //1.4 免费试听的级数： 需要根据收费状态判断
        //tracksForFree    //专辑付费类型
        // 如果专辑不是免费的 设置前五集免费试听
        if(!albumInfo.getPayType().equals(SystemConstant.ALBUM_PAY_TYPE_FREE)){
            //前2集免费试听
            albumInfo.setTracksForFree(2);
            //前30秒免费
            albumInfo.setSecondsForFree(30);
        }
        //1.5 专辑的状态: 默认设置为审核通过()
        albumInfo.setStatus(SystemConstant.TRACK_STATUS_PASS);
        albumInfoMapper.insert(albumInfo); //插入，新增到数据库中
    //---------------------------保存专辑标签属性和值----------------------------
        //2.保存 专辑标签属性和值
       albumAttributeValueVoList.forEach(albumAttributeValueVo -> {
           AlbumAttributeValue albumAttributeValue = new AlbumAttributeValue(); //属性值
           BeanUtils.copyProperties(albumAttributeValueVo, albumAttributeValue);

           //绑定专辑Id.  专辑标签的属性值，需要使用专辑id进行关联，但是这个专辑id不是前端传的，是后端生成的
           albumAttributeValue.setAlbumId(albumInfo.getId());
           albumAttributeValueMapper.insert(albumAttributeValue);  //插入保存
       });
    //---------------------------3.初始化专辑的统计数据----------------------------
        //播放量
        saveAlbumStat(albumInfo.getId() , SystemConstant.ALBUM_STAT_PLAY);   // 播放量 "0401
        saveAlbumStat(albumInfo.getId() , SystemConstant.ALBUM_STAT_SUBSCRIBE);//订阅  "0402"
        saveAlbumStat(albumInfo.getId() , SystemConstant.ALBUM_STAT_BROWSE);//// 购买量  "0403"
        saveAlbumStat(albumInfo.getId() , SystemConstant.ALBUM_STAT_COMMENT);//评论  "0404"

        //4.判断 如果专辑不是私密的，发送mq消息，search服务 将新增专辑数据导入到es中。发送mq消息：只发送专辑id
        if(albumInfo.getIsOpen().equals("1")){
            rabbitTemplate.convertAndSend(
                    RabbitConstant.ALBUM_EXCHANGE , RabbitConstant.ALBUM_UPPER_RK,
                    albumInfo.getId()   );

        }

    }

    @Override
    public Page<AlbumListVo> findUserAlbumPage(Long pageNum, Long pageSize, AlbumInfoQuery albumInfoQuery) {
       //要去mysql中查询，因为前端传过来的数据，需要根据条件进行分页查询，所以需要使用mybatis-plus的分页查询。而且是多表查询
       //将用户id设置到参数中
        albumInfoQuery.setUserId(AuthContextHolder.getUserId());
        // mybatisplus 只需要将 page对象传入+ 配置了分页拦截器 它会自动拼接分页sql
        return albumInfoMapper.selectUserAlbumPage(new Page<AlbumListVo>(pageNum,pageSize),albumInfoQuery);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void removeAlbumInfoById(Long id) {
    //1.先判断专辑是否有声音，如果有还有声音的专辑，不允许删除。【可联系尚庭公寓，如公寓中有房子上架/居住，不允许删除】
    //1.1查询专辑下是否有声音，进行判断
        Long count = trackInfoMapper.selectCount(Wrappers.lambdaQuery(TrackInfo.class).eq(TrackInfo::getAlbumId, id));
        if(count > 0){
            //抛出异常后 全局异常处理器捕获 创建一个失败的Result对象响应。存在声音，删除失败泡异常
            throw new GuiguException(ResultCodeEnum.ALBUM_DELETE_ERROR);
        }
    //1.2删除专辑映射相关信息
        albumInfoMapper.deleteById(id);
    //1.3 删除专辑标签属性和值
      albumAttributeValueMapper.delete(Wrappers.lambdaQuery(AlbumAttributeValue.class).eq(AlbumAttributeValue::getAlbumId, id));
    //1.4删除专辑的统计数据
        albumStatMapper.delete(Wrappers.lambdaQuery(AlbumStat.class).eq(AlbumStat::getAlbumId, id));

        //发送消息
        rabbitTemplate.convertAndSend(
                RabbitConstant.ALBUM_EXCHANGE , RabbitConstant.ALBUM_DOWN_RK,
                id  );
    }

    @Override
    public AlbumInfo getAlbumInfo(Long id) {
        AlbumInfo albumInfo = albumInfoMapper.selectById(id);
        if(albumInfo!=null){
            //查询专辑的属性
            List<AlbumAttributeValue> albumAttributeValues = albumAttributeValueMapper.selectList(Wrappers.lambdaQuery(AlbumAttributeValue.class)
                    .eq(AlbumAttributeValue::getAlbumId, id));

           /* 一样的写法，和上面
           List<AlbumAttributeValue> albumAttributeValues1 = albumAttributeValueMapper.selectList(
                    new LambdaQueryWrapper<AlbumAttributeValue>().eq(AlbumAttributeValue::getAlbumId, id));*/
            albumInfo.setAlbumAttributeValueVoList(albumAttributeValues);
        }

        return albumInfo;
    }

    @Override
    public void updateAlbumInfo(Long id, AlbumInfoVo albumInfoVo) {
        //删除redis中当前专辑的缓存
        redisTemplate.delete("album:cache:["+id+"]");

        //1.更新专辑信息
        AlbumInfo albumInfo = new AlbumInfo();
        BeanUtils.copyProperties(albumInfoVo, albumInfo);
        albumInfo.setId(id);   //设置的是主键Id。albumInfo有继承的BaseEntity属性，所以可以设置主键id
     //   albumInfo.setUserId(AuthContextHolder.getUserId());
        albumInfoMapper.updateById(albumInfo);
        //2.更新专辑标签属性和值
        //2.1得先删除本专辑的所有属性的标签属性和值
        albumAttributeValueMapper.delete(Wrappers.lambdaQuery(AlbumAttributeValue.class)
                .eq(AlbumAttributeValue::getAlbumId, id));
        //2.2然后再更新添加本专辑的所有属性的标签属性和值【和新增saveAlbumInfo方法一样，直接拷贝】
        albumInfoVo.getAlbumAttributeValueVoList().forEach(albumAttributeValueVo -> {
            AlbumAttributeValue albumAttributeValue = new AlbumAttributeValue();
            BeanUtils.copyProperties(albumAttributeValueVo ,albumAttributeValue );
            //绑定专辑id  // 专辑标签属性 需要使用专辑id关联
            albumAttributeValue.setAlbumId(albumInfo.getId());
            albumAttributeValueMapper.insert(albumAttributeValue);
        });

        //4.判断 如果专辑不是私密的，发送mq消息，search服务 将新增专辑数据导入到es中。发送mq消息：只发送专辑id
        if(albumInfo.getIsOpen().equals("1")){
            rabbitTemplate.convertAndSend(
                    RabbitConstant.ALBUM_EXCHANGE , RabbitConstant.ALBUM_UPPER_RK,
                    albumInfo.getId()   );
        }else{
            rabbitTemplate.convertAndSend(
                    RabbitConstant.ALBUM_EXCHANGE , RabbitConstant.ALBUM_DOWN_RK,
                    albumInfo.getId()   );
        }
        albumInfoService.deleteCacheAsync("album:cache:["+id+"]");
       // this.deleteCacheAsync("album:cache:["+id+"]");
    }
    //spring 自动异步执行，我们可以为他配置异步任务的线程池
    @Async  //springboot需要启用异步框架
    public void deleteCacheAsync(String cacheKey){
        try {
            Thread.sleep(3000);
            redisTemplate.delete(cacheKey);

        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }
//-----------------------------------------------专辑声音------------------------------------------------------------
    @Override
    public List<AlbumInfo> findUserAllAlbumList(Long userId) {
        LambdaQueryWrapper<AlbumInfo> wrapper = new LambdaQueryWrapper<AlbumInfo>()
                .select(AlbumInfo::getId, AlbumInfo::getAlbumTitle)
                .eq(AuthContextHolder.getUserId() !=null,AlbumInfo::getUserId, userId)
                .orderByDesc(AlbumInfo::getId);
        return albumInfoMapper.selectList(wrapper);
    }

    @Override
    public Page<AlbumListVo> getAlbumListVoPage(Long pageNum, Long pageSize) {
        Page<AlbumListVo> albumPage = albumInfoMapper.selectUserAlbumPage(new Page<>(pageNum, pageSize), new AlbumInfoQuery());
        return albumPage;
    }

    @Override
    public List<AttributeValueIndex> findAttributesByAlbumId(Long albumId) {
        return albumAttributeValueMapper.selectList(Wrappers.lambdaQuery(AlbumAttributeValue.class)
                .eq(AlbumAttributeValue::getAlbumId, albumId)).stream()
                .map(albumAttributeValue -> {
                    AttributeValueIndex attributeValueIndex = new AttributeValueIndex();
                    BeanUtils.copyProperties(albumAttributeValue, attributeValueIndex);
                    return attributeValueIndex;
                }).collect(Collectors.toList());

    }

    @Override
    public AlbumListVo getAlbumListVo(Long id) {
        return albumInfoMapper.selectAlbumListVo(id);
    }

    @Override
    public AlbumStatVo getAlbumStatVo(Long id) {
        return albumStatMapper.selectAlbumStatVo(id);
    }


    //封装通用的方法---------------------------------------------------------------------------
    //   albumInfo.setStatus(SystemConstant.TRACK_STATUS_PASS);前面已默认设置了专辑状态已审核   //
    private void saveAlbumStat(Long albumId,String albumStatType) {                         //
        AlbumStat albumStat = new AlbumStat();                                              //
        albumStat.setAlbumId(albumId);                                                      //
        albumStat.setStatType(albumStatType);//统计类型                                      //
        albumStat.setStatNum(0);                                                            //
        albumStatMapper.insert(albumStat);                                                  //
    }                                                                                       //
    //----------------------------------------------------------------------------------------
}

